# 指定 CMake 的最低版本要求
cmake_minimum_required(VERSION 3.28.3)

# 定义项目名称和使用的语言
project(kylin_ai_steward_kernel_module LANGUAGES C)

# 设置 C 标准为 C11（适用于 eBPF 程序开发）
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# 查找 clang 编译器
find_program(CLANG_EXECUTABLE NAMES clang)

if(NOT CLANG_EXECUTABLE)
    message(FATAL_ERROR "clang 编译器未找到，请安装 clang")
endif()

# 查找 bpftool
find_program(BPFTOOL_EXECUTABLE NAMES bpftool)

if(NOT BPFTOOL_EXECUTABLE)
    message(FATAL_ERROR "bpftool 未找到，请安装 bpftool")
endif()

# 获取系统架构信息
execute_process(
    COMMAND uname -m
    OUTPUT_VARIABLE SYSTEM_ARCH
    OUTPUT_STRIP_TRAILING_WHITESPACE
)

# 根据系统架构设置目标架构宏定义
if(SYSTEM_ARCH STREQUAL "x86_64")
    set(TARGET_ARCH "__TARGET_ARCH_x86")
elseif(SYSTEM_ARCH STREQUAL "aarch64")
    set(TARGET_ARCH "__TARGET_ARCH_arm64")
else()
    message(WARNING "未知的系统架构: ${SYSTEM_ARCH}，默认使用 x86")
    set(TARGET_ARCH "__TARGET_ARCH_x86")
endif()

# 检查 BTF 支持
set(VMLINUX_BTF "/sys/kernel/btf/vmlinux")

if(EXISTS ${VMLINUX_BTF})
    message(STATUS "BTF 支持可用: ${VMLINUX_BTF}")
    set(HAVE_BTF TRUE)
else()
    message(WARNING "BTF 支持不可用: ${VMLINUX_BTF}")
    set(HAVE_BTF FALSE)
endif()

# 检查关键头文件路径
set(BPF_HEADERS_PATH "/usr/include/bpf")
set(LINUX_HEADERS_PATH "/usr/include/linux")

# 设置 eBPF 编译选项
set(EBPF_COMPILE_FLAGS
    "-O2"
    "-g"
    "-target" "bpf"
    "-D${TARGET_ARCH}"
)

# 添加必要的系统头文件路径
if(EXISTS ${BPF_HEADERS_PATH})
    list(APPEND EBPF_COMPILE_FLAGS "-I" "${BPF_HEADERS_PATH}")
endif()

if(EXISTS ${LINUX_HEADERS_PATH})
    list(APPEND EBPF_COMPILE_FLAGS "-I" "${LINUX_HEADERS_PATH}")
endif()

list(APPEND EBPF_COMPILE_FLAGS "-I" "/usr/include/${SYSTEM_ARCH}-linux-gnu")
list(APPEND EBPF_COMPILE_FLAGS "-I" "${CMAKE_SOURCE_DIR}")

# 如果没有 BTF 支持，检查并使用 vmlinux.h
if(NOT HAVE_BTF)
    set(VMLINUX_H_FILE "${CMAKE_SOURCE_DIR}/vmlinux.h")

    if(EXISTS ${VMLINUX_H_FILE})
        message(STATUS "使用 vmlinux.h 作为 BTF 替代方案")
        list(APPEND EBPF_COMPILE_FLAGS "-include" "${VMLINUX_H_FILE}")
    else()
        message(WARNING "缺少 BTF 支持且 vmlinux.h 不存在")
    endif()
endif()

# 定义 eBPF 源文件和目标文件的完整路径
set(EBPF_SOURCE_FILE "${CMAKE_SOURCE_DIR}/ebpf/syscall_monitor.c")
set(EBPF_OBJECT_FILE "${CMAKE_SOURCE_DIR}/ebpf/syscall_monitor.o")

# 添加自定义命令来编译 eBPF 程序
add_custom_command(
    OUTPUT ${EBPF_OBJECT_FILE}
    COMMAND ${CLANG_EXECUTABLE} ${EBPF_COMPILE_FLAGS} -c ${EBPF_SOURCE_FILE} -o ${EBPF_OBJECT_FILE}
    DEPENDS ${EBPF_SOURCE_FILE}
    COMMENT "正在编译 eBPF 程序: ${EBPF_SOURCE_FILE}"
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
    VERBATIM
)

# 创建一个自定义目标，使得 eBPF 对象文件可以被构建
add_custom_target(ebpf ALL
    DEPENDS ${EBPF_OBJECT_FILE}
    COMMENT "构建 eBPF 模块"
)

# 添加生成 skeleton 的自定义命令
set(SKELETON_HEADER "${CMAKE_SOURCE_DIR}/ebpf/syscall_monitor.skel.h")
add_custom_command(
    OUTPUT ${SKELETON_HEADER}
    COMMAND ${BPFTOOL_EXECUTABLE} gen skeleton ${EBPF_OBJECT_FILE} > ${SKELETON_HEADER}
    DEPENDS ${EBPF_OBJECT_FILE}
    COMMENT "生成 skeleton 头文件"
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
    VERBATIM
)

# 添加 skeleton 目标
add_custom_target(skeleton
    DEPENDS ${SKELETON_HEADER}
    COMMENT "生成 skeleton 头文件"
)

# 编译用户空间程序
add_executable(main "${CMAKE_SOURCE_DIR}/ebpf/main.c")
target_include_directories(main PRIVATE "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}/ebpf")
target_link_libraries(main bpf elf z)

# 添加安装规则
install(TARGETS main DESTINATION bin)

# 添加清理命令
set_directory_properties(PROPERTIES
    ADDITIONAL_CLEAN_FILES "${EBPF_OBJECT_FILE};${SKELETON_HEADER}"
)

# 输出构建信息
message(STATUS "项目名称: ${PROJECT_NAME}")
message(STATUS "系统架构: ${SYSTEM_ARCH}")
message(STATUS "目标架构宏: ${TARGET_ARCH}")
message(STATUS "eBPF 编译器: ${CLANG_EXECUTABLE}")
message(STATUS "源文件路径: ${EBPF_SOURCE_FILE}")
message(STATUS "目标文件路径: ${EBPF_OBJECT_FILE}")
message(STATUS "BTF 支持: ${HAVE_BTF}")